﻿using System;
using System.Diagnostics;

namespace CatUtils.Utils.SpecialUtils.WinConsole
{
    internal class ProcessHelper
    {
        /// <summary>
        /// 创建Process基础配置方法
        /// </summary>
        /// <param name="ProcessFilePath"></param>
        /// <param name="Cmd"></param>
        private Process CreateProcess(string ProcessFilePath, string Cmd)
        {
            Process p = new Process();
            p.StartInfo.FileName = ProcessFilePath;
            p.StartInfo.UseShellExecute = false;        //是否使用操作系统shell启动
            p.StartInfo.RedirectStandardInput = true;   //接受来自调用程序的输入信息
            p.StartInfo.RedirectStandardOutput = true;  //由调用程序获取输出信息
            p.StartInfo.RedirectStandardError = true;   //重定向标准错误输出
            p.StartInfo.Arguments = Cmd;//设定要执行的命令
            Console.WriteLine(Cmd);
            p.Start();
            //获取cmd窗口的输出信息
            p.StandardInput.AutoFlush = true;
            return p;
        }

        /// <summary>
        /// 执行cmd命令
        /// 多命令请使用批处理命令连接符：
        /// <![CDATA[
        /// &:同时执行两个命令
        /// |:将上一个命令的输出,作为下一个命令的输入
        /// &&：当&&前的命令成功时,才执行&&后的命令
        /// ||：当||前的命令失败时,才执行||后的命令]]>
        /// 其他请百度
        /// </summary>
        /// <param name="ProcessFilePath"></param>
        /// <param name="Cmd"></param>
        /// <returns></returns>
        public string RunCmdReadOut(string ProcessFilePath, string Cmd)
        {
            string Relust = "";
            //   Cmd = Cmd.Trim().TrimEnd('&') + " &exit";//说明：不管命令是否成功均执行exit命令，否则当调用ReadToEnd()方法时，会处于假死状态
            using (Process p = CreateProcess(ProcessFilePath, Cmd))
            {
                Relust = p.StandardOutput.ReadToEnd();
                p.WaitForExit();//等待程序执行完退出进程
                p.Close();
            }

            return Relust;
        }

        /// <summary>
        /// 读取错误日志并且关闭，专为FFMPEG使用，不然程序会假死
        /// </summary>
        /// <param name="ProcessFilePath"></param>
        /// <param name="Cmd"></param>
        /// <returns></returns>
        public string RunCmdReadError(string ProcessFilePath, string Cmd)
        {
            string Relust = "";
            using (Process p = CreateProcess(ProcessFilePath, Cmd))
            {
                //获取cmd窗口的输出信息
                Relust = p.StandardError.ReadToEnd();
                p.WaitForExit();//等待程序执行完退出进程
                p.Close();
            }

            return Relust;
        }

        /// <summary>
        /// 异步执行命令行
        /// </summary>
        /// <param name="ProcessFilePath"></param>
        /// <param name="Cmd"></param>
        /// <returns></returns>
        public void RunCmdAsync(string ProcessFilePath, string Cmd, DataReceivedEventHandler receivedEventHandler)
        { //   Cmd = Cmd.Trim().TrimEnd('&') + " &exit";//说明：不管命令是否成功均执行exit命令，否则当调用ReadToEnd()方法时，会处于假死状态
            using (Process p = CreateProcess(ProcessFilePath, Cmd))
            {
                p.ErrorDataReceived += new DataReceivedEventHandler(receivedEventHandler);
                p.OutputDataReceived += new DataReceivedEventHandler(receivedEventHandler);

                p.BeginOutputReadLine();//开始异步读取
                p.BeginErrorReadLine();//开始异步读取

                p.WaitForExit();//等待程序执行完退出进程
                p.Close();
            }
        }
    }
}